﻿using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;

namespace CabConfigProvisioning
{
    public class MemoryCache
    {
        private static MemoryCache _instance = new MemoryCache();

        private Dictionary<string,MemoryFile> _files = new Dictionary<string, MemoryFile>();

        public static MemoryCache Instance
        {
            get { return _instance; }
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public MemoryFile Put(FileInfo file, bool bKeepOriginalName)
        {
            MemoryFile memoryFile = new MemoryFile(this, file, bKeepOriginalName);
            _files[memoryFile.FullName] = memoryFile;
            return memoryFile;
        }

        public MemoryFile Put(FileInfo file)
        {
            return Put(file, true);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public MemoryFile Put(FileInfo file, byte[] content, ushort date, ushort time, ushort attributes)
        {
            MemoryFile memoryFile = new MemoryFile(this, file, content);
            _files[memoryFile.FullName] = memoryFile;
            memoryFile.Date = date;
            memoryFile.Time = time;
            memoryFile.Attributes = attributes;
            return memoryFile;
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public bool Remove(string sFilePath)
        {
            return _files.Remove(sFilePath);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void RemoveAll(List<MemoryFile> files)
        {
            foreach(MemoryFile file in files)
                _files.Remove(file.FullName);
        }

        private string AdaptPath(string sFilePath)
        {
            string sName = Path.GetFileName(sFilePath);
            return MemoryFile.IsCacheFile(sName) ? sName : sFilePath;
        }

        public MemoryFile this[string sFilePath]
        {
            get
            {
                lock (this)
                {
                    MemoryFile memoryFile;
                    return _files.TryGetValue(AdaptPath(sFilePath), out memoryFile) ? memoryFile : null;
                }
            }
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public bool TryGetStream(string sFilePath, out Stream stream)
        {
            MemoryFile memoryFile;
            if (_files.TryGetValue(AdaptPath(sFilePath), out memoryFile))
            {
                stream = memoryFile.Stream;
                return true;
            }
            else
            {
                stream = null;
                return false;
            }
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public bool TryGetStream(string sFilePath, out Stream stream, out ushort pdate, out ushort ptime, out ushort pattribs)
        {
            MemoryFile memoryFile;
            if (_files.TryGetValue(AdaptPath(sFilePath), out memoryFile))
            {
                stream = memoryFile.Stream;
                pdate = memoryFile.Date;
                ptime = memoryFile.Time;
                pattribs = memoryFile.Attributes;
                return true;
            }
            else
            {
                stream = null;
                pdate = 0;
                ptime = 0;
                pattribs = 0;
                return false;
            }
        }
    }
}
